import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'
    show TestDefaultBinaryMessengerBinding, TestWidgetsFlutterBinding;
import 'package:motion_sensors_ohos/motion_sensors_ohos.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();
  final MethodChannel methodChannel = MethodChannel('motion_sensors/method');
  TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
      .setMockMethodCallHandler(
    methodChannel,
        (message) => null,
  );

  test('$AccelerometerEvent are streamed', () async {
    const channelName = 'motion_sensors/accelerometer';
    const sensorData = <double>[1.0, 2.0, 3.0];
    _initializeFakeSensorChannel(channelName, sensorData);
    final event = await AccelerometerEvent.fromList(sensorData);
    expect(event.x, sensorData[0]);
    expect(event.y, sensorData[1]);
    expect(event.z, sensorData[2]);
  });

  test('$GyroscopeEvent are streamed', () async {
    const channelName = 'motion_sensors/gyroscope';
    const sensorData = <double>[3.0, 4.0, 5.0];
    _initializeFakeSensorChannel(channelName, sensorData);
    final event = await GyroscopeEvent.fromList(sensorData);
    expect(event.x, sensorData[0]);
    expect(event.y, sensorData[1]);
    expect(event.z, sensorData[2]);
  });

  test('$MagnetometerEvent are streamed', () async {
    const channelName = 'motion_sensors/magnetometer';
    const sensorData = <double>[8.0, 9.0, 10.0];
    _initializeFakeSensorChannel(channelName, sensorData);
    final event = await MagnetometerEvent.fromList(sensorData);
    expect(event.x, sensorData[0]);
    expect(event.y, sensorData[1]);
    expect(event.z, sensorData[2]);
  });

  test('$OrientationEvent are streamed', () async {
    const channelName = 'motion_sensors/orientation';
    const sensorData = <double>[2.0, 9.0, 6.0];
    _initializeFakeSensorChannel(channelName, sensorData);
    final event = await OrientationEvent.fromList(sensorData);
    expect(event.yaw, sensorData[0]);
    expect(event.pitch, sensorData[1]);
    expect(event.roll, sensorData[2]);
  });

  test('$AbsoluteOrientationEvent are streamed', () async {
    const channelName = 'motion_sensors/absolute_orientation';
    const sensorData = <double>[4.0, 7.0, 1.0];
    _initializeFakeSensorChannel(channelName, sensorData);
    final event = await AbsoluteOrientationEvent.fromList(sensorData);
    expect(event.yaw, sensorData[0]);
    expect(event.pitch, sensorData[1]);
    expect(event.roll, sensorData[2]);
  });

  test('$ScreenOrientationEvent are streamed', () async {
    const channelName = 'motion_sensors/screen_orientation';
    const sensorData = 90.0;
    _initializeFakeSensorChannel1(channelName, sensorData);
    final event = await ScreenOrientationEvent(sensorData);
    expect(event.angle, sensorData);
  });

}

void _initializeFakeSensorChannel1(String channelName, double sensorData) {
  const standardMethod = StandardMethodCodec();
  void emitEvent(ByteData? event) {
    TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
        .handlePlatformMessage(
      channelName,
      event,
          (ByteData? reply) {},
    );
  }

  TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
      .setMockMessageHandler(channelName, (ByteData? message) async {
    final methodCall = standardMethod.decodeMethodCall(message);
    if (methodCall.method == 'listen') {
      emitEvent(standardMethod.encodeSuccessEnvelope(sensorData));
      emitEvent(null);
      return standardMethod.encodeSuccessEnvelope(null);
    } else if (methodCall.method == 'cancel') {
      return standardMethod.encodeSuccessEnvelope(null);
    } else {
      fail('Expected listen or cancel');
    }
  });
}

void _initializeFakeSensorChannel(String channelName, List<double> sensorData) {
  const standardMethod = StandardMethodCodec();
  void emitEvent(ByteData? event) {
    TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
        .handlePlatformMessage(
      channelName,
      event,
          (ByteData? reply) {},
    );
  }

  TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
      .setMockMessageHandler(channelName, (ByteData? message) async {
    final methodCall = standardMethod.decodeMethodCall(message);
    if (methodCall.method == 'listen') {
      emitEvent(standardMethod.encodeSuccessEnvelope(sensorData));
      emitEvent(null);
      return standardMethod.encodeSuccessEnvelope(null);
    } else if (methodCall.method == 'cancel') {
      return standardMethod.encodeSuccessEnvelope(null);
    } else {
      fail('Expected listen or cancel');
    }
  });
}